const NM80211ApFlags = NetworkManager['80211ApFlags'];
const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
+const PortalHelperResult = {
+ CANCELLED: 0,
+ COMPLETED: 1,
+ RECHECK: 2
+};
+
+const PortalHelperIface = '<node> \
+<interface name="org.gnome.Shell.PortalHelper"> \
+<method name="Authenticate"> \
+ <arg type="o" direction="in" name="connection" /> \
+ <arg type="s" direction="in" name="url" /> \
+ <arg type="u" direction="in" name="timestamp" /> \
+</method> \
+<method name="Close"> \
+ <arg type="o" direction="in" name="connection" /> \
+</method> \
+<method name="Refresh"> \
+ <arg type="o" direction="in" name="connection" /> \
+</method> \
+<signal name="Done"> \
+ <arg type="o" name="connection" /> \
+ <arg type="u" name="result" /> \
+</signal> \
+</interface> \
+</node>';
+const PortalHelperProxy = Gio.DBusProxy.makeProxyWrapper(PortalHelperIface);
+
function ssidCompare(one, two) {
if (!one || !two)
return false;
this._activeConnections = [ ];
this._connections = [ ];
+ this._connectivityQueue = [ ];
this._mainConnection = null;
this._mainConnectionIconChangedId = 0;
this._client.connect('notify::primary-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::activating-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::active-connections', Lang.bind(this, this._syncVPNConnections));
+ this._client.connect('notify::connectivity', Lang.bind(this, this._syncConnectivity));
this._client.connect('device-added', Lang.bind(this, this._deviceAdded));
this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved));
this._settings.connect('new-connection', Lang.bind(this, this._newConnection));
}
this._updateIcon();
+ this._syncConnectivity();
},
_syncVPNConnections: function() {
_syncNMState: function() {
this.indicators.visible = this._client.manager_running;
this.menu.actor.visible = this._client.networking_enabled;
+
+ this._syncConnectivity();
+ },
+
+ _flushConnectivityQueue: function() {
+ if (this._portalHelperProxy) {
+ for (let item of this._connectivityQueue)
+ this._portalHelperProxy.CloseRemote(item);
+ }
+
+ this._connectivityQueue = [];
+ },
+
+ _closeConnectivityCheck: function(path) {
+ let index = this._connectivityQueue.indexOf(path);
+
+ if (index >= 0) {
+ if (this._portalHelperProxy)
+ this._portalHelperProxy.CloseRemote(path);
+
+ this._connectivityQueue.splice(index, 1);
+ }
+ },
+
+ _portalHelperDone: function(proxy, emitter, parameters) {
+ let [path, result] = parameters;
+
+ if (result == PortalHelperResult.CANCELLED) {
+ // Keep the connection in the queue, so the user is not
+ // spammed with more logins until we next flush the queue,
+ // which will happen once he chooses a better connection
+ // or we get to full connectivity through other means
+ } else if (result == PortalHelperResult.COMPLETED) {
+ this._closeConnectivityCheck(path);
+ return;
+ } else if (result == PortalHelperResult.RECHECK) {
+ this._client.check_connectivity_async(null, Lang.bind(this, function(client, result) {
+ try {
+ let state = client.check_connectivity_finish(result);
+ if (state >= NetworkManager.ConnectivityState.FULL)
+ this._closeConnectivityCheck(path);
+ } catch(e) { }
+ }));
+ } else {
+ log('Invalid result from portal helper: ' + result);
+ }
+ },
+
+ _syncConnectivity: function() {
+ if (this._mainConnection == null ||
+ this._mainConnection.state != NetworkManager.ActiveConnectionState.ACTIVATED) {
+ this._flushConnectivityQueue();
+ return;
+ }
+
+ let isPortal = this._client.connectivity == NetworkManager.ConnectivityState.PORTAL;
+ // For testing, allow interpreting any value != FULL as PORTAL, because
+ // LIMITED (no upstream route after the default gateway) is easy to obtain
+ // with a tethered phone
+ // NONE is also possible, with a connection configured to force no default route
+ // (but in general we should only prompt a portal if we know there is a portal)
+ if (GLib.getenv('GNOME_SHELL_CONNECTIVITY_TEST') != null)
+ isPortal = isPortal || this._client.connectivity < NetworkManager.ConnectivityState.FULL;
+ if (!isPortal)
+ return;
+
+ let path = this._mainConnection.get_path();
+ for (let item of this._connectivityQueue) {
+ if (item == path)
+ return;
+ }
+
+ let timestamp = global.get_current_time();
+ if (this._portalHelperProxy) {
+ this._portalHelperProxy.AuthenticateRemote(path, '', timestamp);
+ } else {
+ new PortalHelperProxy(Gio.DBus.session, 'org.gnome.Shell.PortalHelper',
+ '/org/gnome/Shell/PortalHelper', Lang.bind(this, function (proxy, error) {
+ if (error) {
+ log('Error launching the portal helper: ' + error);
+ return;
+ }
+
+ this._portalHelperProxy = proxy;
+ proxy.connectSignal('Done', Lang.bind(this, this._portalHelperDone));
+
+ proxy.AuthenticateRemote(path, '', timestamp);
+ }));
+ }
+
+ this._connectivityQueue.push(path);
},
_updateIcon: function() {